import * as Koa from 'koa';
import { pipe, cors } from './middleware';
import { RouteManager } from './common';
import Router = require('koa-router');
import bodyParser = require("koa-bodyparser");
import https = require("https");
import fs = require("fs");
import path = require("path");
const convert = require('koa-convert');
const logger = require('koa-logger');
const webconfig = require("../webconfig").webconfig;
const compress = require('koa-compress');

export class Server {
    private router: Router;
    private app: Koa;
    private hostName: string = "0.0.0.0";

    constructor() {
        this.app = new Koa();
        this.router = new Router();
        this.init();
    }

    /**
     * 初始化方法
     * 顺序必须为:
     * (1)Parser
     * (2)MiddleWares
     * (3)Routers
     */
    private init() {
        this.registerParser();
        this.registerMiddleWares();
        this.registerRouters();
    }

    /**
     * http通信协议
     * (1)json
     * (2)form
     * (3)text
     */
    private registerParser() {
        this.app.use(bodyParser({
            extendTypes: {
                json: ['application/json'],
                form: ['application/x-www-form-urlencoded'],
                text: ['text/plain']
            },
            jsonLimit: "5mb",
            strict: false,
            onerror: (err: any, ctx) => {
                err.status = err.status || 422;
                err.body = err.body ? "请求数据有误！请求格式为：" + err.body : "请求数据有误！";
                let e = {
                    "code": err.status,
                    "msg": err.body
                };
                ctx.throw(JSON.stringify(e), err.status);
            }
        }));

        this.app.use(compress({
            filter: function (content_type) {
                return /json/i.test(content_type)
            },
            threshold: 2048 * 100,
            flush: require('zlib').Z_SYNC_FLUSH
        }));
    }

    /**
     * 挂载中间件
     * cors：跨域
     * pipe：异常处理
     * logger：日志 , logger()
     */
    private registerMiddleWares() {
        this.app.use(convert.compose(
            cors(),
            pipe(),
            logger()
        ));
    }

    /**
     * 挂载路由
     */
    private registerRouters() {
        RouteManager.Current.Routes.forEach((controller, config) => {
            let controllers = Array.isArray(controller) ? controller : [controller];
            controllers.forEach((controller) =>
                this.router[config.method](config.path, controller.bind(config.target))
            );
        });

        RouteManager.Current.Destory();

        this.app.use(this.router.routes());
        this.app.use(this.router.allowedMethods());
    }

    /**
     * 启动服务
     * 默认端口：8886
     */
    listen() {
        let maxListeners = Math.max(this.app.getMaxListeners() - 1, 0);
        this.app.setMaxListeners(maxListeners);
        console.log("事件监听数为：", maxListeners);

        // 监听 http
        let port = process.env.port || 8887;
        this.app.listen(port, this.hostName, () => {
            console.log('FBS服务器启动成功，监听端口： %d, in %s mode', port, this.app.env);
        });

        // 监听 https        
        let httpsPort = process.env.httpsPort || 8886;
        let dir = "/extracted/fbs/certificate/";
        if (process.env.NODE_ENV == "development") dir = "/certificate/";
        //开启监听Https端口
        let options = {
            key: fs.readFileSync(path.normalize(process.cwd() + dir + 'ca.key')),
            cert: fs.readFileSync(path.normalize(process.cwd() + dir + 'ca.crt'))
        };

        let server = https.createServer(options, this.app.callback());
        server.listen(httpsPort, this.hostName, () => {
            console.log('FBS Https服务器启动成功，监听端口： %d, in %s mode', httpsPort, this.app.env);
        });
    }
}